package keer.httpinterface.utils;

import keer.httpinterface.annotation.Alias;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * AnnotationInfo类继承自LinkedHashMap，用于存储注解的相关信息
 * 它不仅存储直接关联到特定注解的属性和值，还存储该注解所包含的其他注解的信息
 *
 * @author Keer
 * @version 1.0.0
 */
public class AnnotationInfo extends LinkedHashMap<String, Object> {
    // 存储当前注解所包含的其他注解的信息
    private Map<Class<? extends Annotation>, AnnotationInfo> annotations;
    // 当前注解的类型
    private final Class<? extends Annotation> annotationType;
    // 存储当前注解的属性别名信息
    private final List<AliasHolder> propertyAliases;
    // 存储当前注解的父别名信息
    private final List<AliasHolder> parentAliases;
    // 当前注解实例
    private final Annotation annotation;
    // 当前注解的默认值映射
    private final Map<String,Object> defaultValues;

    /**
     * 私有构造函数，初始化AnnotationInfo实例
     *
     * @param annotation 当前注解实例
     */
    private AnnotationInfo(Annotation annotation) {
        this.annotationType = annotation.annotationType();
        this.annotations = new LinkedHashMap<>();
        this.propertyAliases = new ArrayList<>();
        this.parentAliases = new ArrayList<>();
        this.annotation = annotation;
        this.defaultValues = new HashMap<>();
    }

    /**
     * 获取当前注解实例
     *
     * @return 当前注解实例
     */
    public Annotation getAnnotation() {
        return annotation;
    }

    /**
     * 获取当前注解的类型
     *
     * @return 当前注解的类型
     */
    public Class<? extends Annotation> getAnnotationType() {
        return annotationType;
    }

    /**
     * 获取当前注解所包含的所有注解信息
     *
     * @return 当前注解所包含的所有注解信息数组
     */
    public AnnotationInfo[] getDeclaredAnnotations() {
        return annotations.values().toArray(new AnnotationInfo[0]);
    }

    /**
     * 根据注解类型获取指定的注解信息，可选择是否包括继承的注解
     *
     * @param annotationType 注解类型
     * @param includeInherited 是否包括继承的注解
     * @return 指定类型的注解信息，如果不存在则返回null
     */
    public AnnotationInfo getDeclaredAnnotation(Class<? extends Annotation> annotationType, boolean includeInherited) {
        AnnotationInfo info = annotations.get(annotationType);
        if (info != null) {
            return info;
        }
        if (includeInherited) {
            for (AnnotationInfo i : annotations.values()) {
                AnnotationInfo a = i.getDeclaredAnnotation(annotationType, Boolean.TRUE);
                if (a != null) {
                    return a;
                }
            }
        }
        return null;
    }

    /**
     * 创建并初始化AnnotationInfo实例
     *
     * @param annotation 注解实例
     * @return 初始化后的AnnotationInfo实例
     */
    public static AnnotationInfo of(Annotation annotation) {
        AnnotationInfo info = new AnnotationInfo(annotation);
        initProperties(info);
        initAnnotations(info);
        return info;
    }

    /**
     * 初始化注解的属性信息，包括默认值、实际值和别名信息
     *
     * @param info 当前注解信息实例
     */
    public static void initProperties(AnnotationInfo info) {
        Method[]methods = info.annotationType.getDeclaredMethods();
        for (Method m : methods) {
            try {
                Object defaultVal = m.getDefaultValue();
                info.defaultValues.put(m.getName(), defaultVal);
                Object o = m.invoke(info.annotation);
                info.put(m.getName(), o);
                Alias alias = m.getDeclaredAnnotation(Alias.class);
                if (alias != null) {
                    AliasHolder holder = new AliasHolder();
                    holder.alias = alias;
                    holder.srcProperty = m.getName();
                    holder.info = info;
                    if (alias.annotation().equals(Annotation.class)) {
                        holder.targetType = info.annotationType;
                        info.propertyAliases.add(holder);
                    } else {
                        holder.targetType = alias.annotation();
                        info.parentAliases.add(holder);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        for (AliasHolder holder : info.propertyAliases) {
            setByAlias(info, holder);
        }
    }

    /**
     * 初始化注解所包含的其他注解的信息
     *
     * @param info 当前注解信息实例
     */
    private static void initAnnotations(AnnotationInfo info) {
        info.annotations = new LinkedHashMap<>();
        Annotation[] parent = info.annotationType.getDeclaredAnnotations();
        for (Annotation a : parent) {
            AnnotationInfo ai = new AnnotationInfo(a);
            initProperties(ai);
            for (AliasHolder holder : info.parentAliases) {
                if (holder.alias.annotation().equals(a.annotationType())) {
                    setByAlias(ai, holder);
                }
            }
            info.annotations.put(a.annotationType(), ai);
            if (!a.annotationType().getPackage().getName().equals("java.lang.annotation")) {
                initAnnotations(ai);
            }
        }
    }

    /**
     * 根据别名信息设置注解的属性值
     *
     * @param target 目标注解信息实例
     * @param holder 别名持有者，包含别名信息
     */
    private static void setByAlias(AnnotationInfo target, AliasHolder holder) {
        Object defaultVal = target.defaultValues.get(holder.alias.property());
        Object value = target.get(holder.alias.property());
        Object newValue = holder.info.get(holder.srcProperty);
        if (newValue != null) {
            if (value == null || Objects.deepEquals(defaultVal, value)) {
                target.put(holder.alias.property(), holder.info.get(holder.srcProperty));
            }
        }
    }

    /**
     * 别名持有者类，用于存储注解别名的相关信息
     */
    private static class AliasHolder {
        private Class<? extends Annotation> targetType;
        private Alias alias;
        private String srcProperty;
        private AnnotationInfo info;
    }
}
